clear all;
close all;

%  =======================================================================================================================================================
% 
%  Code Description: 
%  This codefile executes the analysis of funds' reported portfolios versus funds' portfolios after looking through fund shares, 
%  as described in Section 3.2.1 and the internet appendix A ("Portfolio Look-Through"), as well as table 2.
% 
%  =======================================================================================================================================================
% 
%  Major output:
%  - Table 2: Reported versus look-through portfolios.
%  =======================================================================================================================================================
% 
%  General disclaimer:
%  This file directory produces replication code for "Connected Funds". 
%  Because we cannot share the underlying data provided by the Bundesbank's Research Data and Service Centre (RDSC) and other subscription data sources, 
%  we have included pseudo data to show how the raw data are formatted. 
%  Other researchers can go through a similar approval and subscription process to obtain the underlying data. (2023-04-06)
% 
%  =======================================================================================================================================================


%% Set project directory

projectPath = 'C:\ConnectedFunds_Codebase\';
addpath(projectPath)

% Add functions folders
addpath('C:\ConnectedFunds_Codebase\Code\matlab_functions');

cd 'C:\ConnectedFunds_Codebase\Code\'

% Set window state to get figures printed in full-screen
set(groot, 'defaultFigureWindowState', 'maximized')

% Get current time
StartTotalTime = datetime;


%%  ======================================================================== Section 1: Preparations ===============================================================================

min_date = 200909;
maxDatum = 202006;
disp('max datum set to june 2020'),

% Set threshold parameter for winsorizing
threshold_priceimpact_equities = 0.85;

% Get IFS data
load(strcat(projectPath, 'Data\IFS\IFS_All_CleanData'));

data = IFS_All;
clear IFS_All

% Drop all data prior to min_date and after maxDatum
if exist('dates', 'var')
    tt = find(~ismember(data.DATUM, dates));
else
    tt = find(data.DATUM < min_date | data.DATUM > maxDatum);
end

data(tt, :) = [];

data = data(data.artmittel <= 3 | data.artmittel == 7, :); % keep equity/bond/mixed funds and fund of funds
data(data.etf == 1, :)              = [];  % drop etfs
data(data.DISF == 1, :)             = [];  % drop dissolved fonds
data(data.FONDSVERM <= 0, :)        = [];  % drop if erroneous TNA
data(data.leverage > 2, :)          = [];  % drop funds with extreme leverage ratios. 

umonth = unique(data.DATUM);
Tmonth = length(umonth);

% Generate number and list of unique funds in sample
ufund = unique(data.ISIN);
Nfunds = length(ufund);

[~, idxWhereFund] = ismember(data.ISIN, ufund);
data.fundid = idxWhereFund;


%% Generate result matrices

% Fund level
Fund_Artmittel                      = NaN(Tmonth, Nfunds);
Fund_Spezial                        = NaN(Tmonth, Nfunds);
Fund_Fondsverm                      = NaN(Tmonth, Nfunds);
Fund_Bilanzsumme                    = NaN(Tmonth, Nfunds);
Fund_Leverage                       = NaN(Tmonth, Nfunds);
Fund_PriceImpact_NoLookThrough      = NaN(Tmonth, Nfunds);
Fund_PriceImpact_LookThrough        = NaN(Tmonth, Nfunds);
Fund_MarketableAssets               = NaN(Tmonth, Nfunds);
Fund_OtherAssets                    = NaN(Tmonth, Nfunds);
Fund_FundShares                     = NaN(Tmonth, Nfunds);
Fund_TotalAssets                    = NaN(Tmonth, Nfunds);
Fund_Cash                           = NaN(Tmonth, Nfunds);

% Fund-level asset concentration
... All reported assets
Fund_HHI_LookThrough   = nan(Tmonth, size(ufund, 1));
Fund_HHI_NoLookThrough = nan(Tmonth, size(ufund, 1));

... Only direct bond and stock holdings
Fund_HHI_LookThroughDirect   = nan(Tmonth, size(ufund, 1));
Fund_HHI_NoLookThroughDirect = nan(Tmonth, size(ufund, 1));

... All reported assets
Fund_NrSecurities_LookThrough   = nan(Tmonth, size(ufund, 1));
Fund_NrSecurities_NoLookThrough = nan(Tmonth, size(ufund, 1));

... Only direct bond and stock holdings
Fund_NrSecurities_LookThroughDirect   = nan(Tmonth, size(ufund, 1));
Fund_NrSecurities_NoLookThroughDirect = nan(Tmonth, size(ufund, 1));

% Additional statistics
Agg_NumberISINs_Publikum        = NaN(Tmonth, 4);
Agg_NumberISINs_Spezial         = NaN(Tmonth, 4);

Agg_MarketableAssets_Publikum   = NaN(Tmonth, 4);
Agg_MarketableAssets_Spezial    = NaN(Tmonth, 4);

Agg_OtherAssets_Publikum = NaN(Tmonth, 4);
Agg_OtherAssets_Spezial  = NaN(Tmonth, 4);

Agg_FundShares_Publikum         = NaN(Tmonth, 4);
Agg_FundShares_Spezial          = NaN(Tmonth, 4);

TotalShare_MarketableAssets     = NaN(Tmonth, 1);
TotalShare_OtherAssets          = NaN(Tmonth, 1);
TotalShare_FundShares           = NaN(Tmonth, 1);

Agg_TotalAssets                 = NaN(Tmonth, 2);

Tmonth


%%  ======================================== Section 2: Compute fund-level characteristics for reported and look-through portfolios ===========================================================


for t = 1 : Tmonth-1 
    
    % Get current time
    StartTime = datetime;
    
    umonth(t),

    % Get funds' fund-level data
    fund_data = data(data.DATUM == umonth(t) & data.leverage >= 0 ...
        & ~isinf(data.leverage) & ~isnan(data.leverage), :);
        
    % Get funds' portfolio data
    load(strcat(projectPath, 'Data\IFS\mat\IFS_Holdings_', num2str(umonth(t))), 'IFS_Holdings');
    load(strcat(projectPath, 'Data\IFS\mat\IFS_Holdings_NoISIN_', num2str(umonth(t))), 'IFS_Holdings_NoISIN');
    load(strcat(projectPath, 'Data\CSDB\mat\CSDB_', num2str(umonth(t))));    
    CSDB.Properties.VariableNames("ISIN") = "SECCODE";

    if umonth(t)<201412
        ... Securities with ISIN
        IFS_Holdings = outerjoin(IFS_Holdings, CSDB(:, {'SECCODE', 'ESA_INS_1995'}), Keys="SECCODE", MergeKeys=true, Type='left');
        IFS_Holdings.Properties.VariableNames("ESA_INS_1995") = "ESA_INS_IFS";
        IFS_Holdings.ESA_INS_IFS = strrep(IFS_Holdings.ESA_INS_IFS, '.', '_');
       
        IFS_Holdings.ESA1995 = strrep(IFS_Holdings.ESA1995, '.', '_');
        IFS_Holdings.Properties.VariableNames("ESA1995") = "ESA2010_SEKTOR";

        ... Securities without ISIN
        IFS_Holdings_NoISIN = outerjoin(IFS_Holdings_NoISIN, CSDB(:, {'SECCODE', 'ESA_INS_1995'}), Keys="SECCODE", MergeKeys=true, Type='left');
        IFS_Holdings_NoISIN.Properties.VariableNames("ESA_INS_1995") = "ESA_INS_IFS";
        IFS_Holdings_NoISIN.ESA_INS_IFS = strrep(IFS_Holdings_NoISIN.ESA_INS_IFS, '.', '_');
       
        IFS_Holdings_NoISIN.ESA1995 = strrep(IFS_Holdings_NoISIN.ESA1995, '.', '_');
        IFS_Holdings_NoISIN.Properties.VariableNames("ESA1995") = "ESA2010_SEKTOR";

    else
        ... Securities with ISIN
        IFS_Holdings = outerjoin(IFS_Holdings, CSDB(:, {'SECCODE', 'ESA_INS_2010'}), Keys="SECCODE", MergeKeys=true, Type='left');
        IFS_Holdings.Properties.VariableNames("ESA_INS_2010") = "ESA_INS_IFS";

        IFS_Holdings.Properties.VariableNames("ESA2010") = "ESA2010_SEKTOR";

         ... Securities without ISIN
        IFS_Holdings_NoISIN = outerjoin(IFS_Holdings_NoISIN, CSDB(:, {'SECCODE', 'ESA_INS_2010'}), Keys="SECCODE", MergeKeys=true, Type='left');
        IFS_Holdings_NoISIN.Properties.VariableNames("ESA_INS_2010") = "ESA_INS_IFS";

        IFS_Holdings_NoISIN.Properties.VariableNames("ESA2010") = "ESA2010_SEKTOR";
    end

    ... transform to cellstr
    IFS_Holdings.ESA2010_SEKTOR         = cellstr(IFS_Holdings.ESA2010_SEKTOR);
    IFS_Holdings_NoISIN.ESA2010_SEKTOR  = cellstr(IFS_Holdings_NoISIN.ESA2010_SEKTOR);
    IFS_Holdings.ESA_INS_IFS            = cellstr(IFS_Holdings.ESA_INS_IFS);
    IFS_Holdings_NoISIN.ESA_INS_IFS     = cellstr(IFS_Holdings_NoISIN.ESA_INS_IFS);
    IFS_Holdings.CNTRY                  = cellstr(IFS_Holdings.CNTRY);
    IFS_Holdings_NoISIN.CNTRY           = cellstr(IFS_Holdings_NoISIN.CNTRY);

    ... AMOUNT is denominated in €T
    IFS_Holdings.AMOUNT = IFS_Holdings.AMOUNT * 1000;
    IFS_Holdings_NoISIN.AMOUNT = IFS_Holdings_NoISIN.AMOUNT * 1000; 
    
    fund_Holdings_WithISIN = IFS_Holdings;
    fund_Holdings_NoISIN   = IFS_Holdings_NoISIN;

    clear IFS_Holdings* 
    
    fund_data = sortrows(fund_data, 'ISIN');
    
    % Get funds that are active in month t 
    uinvestor  = fund_data.ISIN; 
    
    % Flag those funds' holdings
    [~, investor] = ismember(fund_Holdings_WithISIN.ISIN, uinvestor);
    
    % Eliminate holdings from funds with invalid leverage fields
    fund_Holdings_WithISIN(investor == 0, :) = [];
    investor(investor == 0) = [];
    
    % Get list of unique securities held by remaining funds
    uwpkenn = unique(fund_Holdings_WithISIN.SECCODE);
    
    % Find these securities in funds' portfolios
    [~, idxWhereUwpkenn] = ismember(fund_Holdings_WithISIN.SECCODE, uwpkenn);
    

    %% Build portfolio data matrix: investors/funds by securities held
    Portfolios = zeros(length(uinvestor), length(uwpkenn));
    
    PriceImpact_FundShares   = zeros(length(uwpkenn), 1);
    ISIN_FundShares          = startsWith(fund_Holdings_WithISIN.ESA_INS_IFS, 'F_52'); % identify fund shares
    ISIN_DE                  = startsWith(fund_Holdings_WithISIN.CNTRY, 'DE');
    ForeignFundShares        = ~startsWith(fund_Holdings_WithISIN.CNTRY, 'DE') & startsWith(fund_Holdings_WithISIN.ESA_INS_IFS, 'F_52');
    
    % Get foreign fund shares
    ForeignFundShares = fund_Holdings_WithISIN(ForeignFundShares, {'ISIN', 'SECCODE', 'AMOUNT'});
    
    PriceImpact_AssetSector_IFS = cell(length(uwpkenn),1);
    
    for tt = 1 : length(idxWhereUwpkenn)
        PriceImpact_FundShares(idxWhereUwpkenn(tt))       = ISIN_FundShares(tt);
        PriceImpact_AssetSector_IFS(idxWhereUwpkenn(tt))  = fund_Holdings_WithISIN.ESA2010_SEKTOR(tt);
        if idxWhereUwpkenn(tt) > 0
            Portfolios(investor(tt), idxWhereUwpkenn(tt)) = Portfolios(investor(tt), idxWhereUwpkenn(tt)) + ...
                max(0, fund_Holdings_WithISIN.AMOUNT(tt)); % only long positions
        end
    end
    

    %% Calculate number of unique ISINs held by different fund types
    for artmittel = [1 2 3 7]
        if artmittel < 7
            Agg_NumberISINs_Publikum(t, artmittel) = sum(sum(Portfolios(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 0, :)) > 0);
            Agg_NumberISINs_Spezial(t, artmittel)  = sum(sum(Portfolios(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 1, :)) > 0);
        else
            Agg_NumberISINs_Publikum(t, 4) = sum(sum(Portfolios(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 0, :)) > 0);
            Agg_NumberISINs_Spezial(t, 4)  = sum(sum(Portfolios(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 1, :)) > 0);
        end
    end
      

    %% Drop assets that are not held by any fund (due to reporting of negative holdings)
    i = find(sum(Portfolios) == 0)';
    
    Portfolios(:, i)                  = [];
    PriceImpact_AssetSector_IFS(i)    = [];
    PriceImpact_FundShares(i)         = [];
    uwpkenn(i)                        = [];
    
    clear i
    
    % Add cash to portfolio matrix
    Portfolios = [Portfolios, 1000 * max(0, fund_data.BANKG)]; 
    

    %% Generate vector of funds' other assets, that are not marketable
    Portfolios_OtherAssets = zeros(length(uinvestor), 1); 
    
    [~, investor] = ismember(fund_Holdings_NoISIN.ISIN, uinvestor);
    
    for tt = 1 : length(investor)
        if investor(tt) > 0
            Portfolios_OtherAssets(investor(tt)) =  Portfolios_OtherAssets(investor(tt)) + ...
                max(fund_Holdings_NoISIN.AMOUNT(tt), 0); % only long positions
        end
    end
    

    %% Get ESA instrument code and issuer country for all wps held by funds
    WP_AssetType        = cell(length(uwpkenn), 1);
    WP_IssuerCountry    = cell(length(uwpkenn), 1);
    WP_IssuerType       = cell(length(uwpkenn), 1);
    
    [~, idxWhereWPKENN] = ismember(uwpkenn, fund_Holdings_WithISIN.SECCODE);
    
    % Get instrument type and issuer country from fund data for each security position held by funds
    WP_AssetType(idxWhereWPKENN > 0)     = fund_Holdings_WithISIN.ESA_INS_IFS(idxWhereWPKENN(idxWhereWPKENN > 0));
    WP_IssuerType(idxWhereWPKENN > 0)    = fund_Holdings_WithISIN.ESA2010_SEKTOR(idxWhereWPKENN(idxWhereWPKENN > 0));
    WP_IssuerCountry(idxWhereWPKENN > 0) = fund_Holdings_WithISIN.CNTRY(idxWhereWPKENN(idxWhereWPKENN > 0));
        

    %% Generate fund share matrix (Portfolios_FundShares) and adjust securities portfolio matrix (Portfolios)
    isin_funds = unique([uinvestor; uwpkenn(PriceImpact_FundShares > 0)]);
    
    Portfolios_FundShares                                       = zeros(length(uinvestor), length(uinvestor));
    [~, idx_WhereFundShares]                                    = ismember(uinvestor, uwpkenn);
    
    % Write fund shares into crossholdings matrix
    Portfolios_FundShares(:, idx_WhereFundShares > 0)           = Portfolios(:, idx_WhereFundShares(idx_WhereFundShares > 0));
    
    % Eliminate fund shares from portfolio matrix
    Portfolios(:, idx_WhereFundShares(idx_WhereFundShares > 0)) = 0;
     

    %% Get vector of security-level amihud ratios (available from 12/2015)
    if umonth(t) >= 201512                   
               
        % Load security-level amihud ratios. Based on CSDB data, these are computed as described in the Discussion Paper version of this paper: 
        % https://www.bundesbank.de/resource/blob/842638/e3d0407c607b42420c9eb251cf9c7953/mL/2020-08-28-dkp-48-data.pdf
        CSDB_data = load(strcat(projectPath, 'Data\CSDB\mat\Amihud_', num2str(umonth(t))));
        CSDB_data = CSDB_data.data;
        
        total_security_share               = cellstr(CSDB_data.ESA_INS_2010);
        CSDB_assettype  = 1 * startsWith(total_security_share, 'F_3') + ...  % bond
            2 * startsWith(total_security_share, 'F_51') + ... % equity
            3 * startsWith(total_security_share, 'F_52');      % fund shares
        
        total_security_share               = cellstr(CSDB_data.ESA_ISSUER_2010);
        CSDB_issuertype = total_security_share;
        clear x;
        
        PriceImpact             = NaN(length(uwpkenn), 1);
        PriceImpact_AssetType   = NaN(length(uwpkenn), 1);
        PriceImpact_AssetSector = cell(length(uwpkenn), 1);
        
        % Find ISINs of marketable assets (uins_bonds / uins_equities) from CSDB data in uwpkenn
        [~, idxWhereCSDBIsin] = ismember(uwpkenn, CSDB_data.ISIN);
        
        PriceImpact(idxWhereCSDBIsin > 0) = CSDB_data.amihud_proxy1(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));
                
        % Add cash
        PriceImpact = [PriceImpact; 0];  
        
        % Get instrument type from CSDB for each security position with amihud ratios available
        PriceImpact_AssetType(idxWhereCSDBIsin > 0)              = CSDB_assettype(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));  
        PriceImpact_AssetType(isnan(PriceImpact_AssetType) == 1) = 3; % other asset
        PriceImpact_AssetSector(idxWhereCSDBIsin > 0)            = CSDB_issuertype(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));
        
        clear idx* asset investor fund_Holdings* tt CSDB* asset_type;
        
        % For assets with missing amihud ratios: check whether previous month is available. If so, replace by that value.
        if t > 1 
            i               = find(isnan(PriceImpact) == 1);
            uwpkenn_missing = uwpkenn(i);
            
            CSDB_data_Lag   = load(strcat(projectPath, 'Data\CSDB\mat\Amihud_', num2str(umonth(t - 1)))); 
            CSDB_data_Lag   = CSDB_data_Lag.data;
            
            [~, idxWhereUwpkennMissing]                                = ismember(CSDB_data_Lag.ISIN, uwpkenn_missing);
            amihud                                                     = NaN(length(uwpkenn_missing), 1);
            amihud(idxWhereUwpkennMissing(idxWhereUwpkennMissing > 0)) = CSDB_data_Lag.amihud_proxy1(idxWhereUwpkennMissing > 0);
                        
            PriceImpact(i)              = amihud;
            
            clear i uwpkenn_missing CSDB_data_Lag idxWhereUwpkennMissing amihud;
        end   
        
        %  Winsorize amihud ratios
        idxWhereAssetType               = find(PriceImpact_AssetType == 2);
        tmp                             = PriceImpact(idxWhereAssetType);
        q                               = quantile(tmp, threshold_priceimpact_equities);
        tmp(tmp > q)                    = q;        
        PriceImpact(idxWhereAssetType)  = tmp;       

        clear idxWhereAssetType tmp q;
        
    end
    
    
    %% Filter out missreported fund share cross-holdings
    
    % Stage 1: drop erroneous holdings 
    TotalAssets                     = sum(Portfolios')' + sum(Portfolios_FundShares')' + sum(Portfolios_OtherAssets, 2);
    ratio                           = Portfolios_FundShares ./ repmat(TotalAssets', length(TotalAssets), 1);
    idx_fund                        = find(ratio > 1.05);
    Portfolios_FundShares(idx_fund) = 0;
    length(idx_fund);
    sum(Portfolios_FundShares(:));    
    
    % Stage 2: check that aggregate fund liabilities are at most the reported total assets
    TotalAssets      = sum(Portfolios')' + sum(Portfolios_FundShares')' + sum(Portfolios_OtherAssets, 2);
    TotalLiabilities = sum(Portfolios_FundShares)';
    idx_fund         = find(TotalAssets < TotalLiabilities);
    nit              = 0;
    
    while isempty(idx_fund) == 0
        nit = nit + 1;
        
        Portfolios_FundShares(:, idx_fund) = repmat((TotalAssets(idx_fund) ./ TotalLiabilities(idx_fund))', length(TotalAssets), 1) .* Portfolios_FundShares(:, idx_fund);
        
        TotalAssets      = sum(Portfolios')' + sum(Portfolios_FundShares')' + sum(Portfolios_OtherAssets, 2);
        TotalLiabilities = sum(Portfolios_FundShares)';
        idx_fund         = find(TotalAssets < TotalLiabilities);
        
        sum(Portfolios_FundShares(:));
    end
    
    clear idx_fund;
    
    
    %%  Record some summary stats
    
    % Get system size
    Agg_TotalAssets(t, :)             = [1000 * sum(fund_data.bilanzsumme) sum(Portfolios(:)) + sum(Portfolios_OtherAssets(:)) + sum(Portfolios_FundShares(:))];
    
    % By fund type (SPEZIAL: 0/1) and asset type (artmittel: equity (1), bond (2), mixed securities (3) or fund-of-fund (7)): Calculate aggregate marketable assets, fundshares and other assets.
    for artmittel = [1 : 3 7]
        if artmittel <= 3
            k = artmittel;
        else
            k = 4;
        end
        
        idxWhereArtmittelPubFund                = find(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 0);
        Agg_MarketableAssets_Publikum(t, k)     = sum(vect(Portfolios(idxWhereArtmittelPubFund, :)));
        Agg_OtherAssets_Publikum(t, k)          = sum(vect(Portfolios_OtherAssets(idxWhereArtmittelPubFund, :)));
        Agg_FundShares_Publikum(t, k)           = sum(vect(Portfolios_FundShares(idxWhereArtmittelPubFund, :)));
        
        idxWhereArtmittelSpezFund               = find(fund_data.artmittel == artmittel & fund_data.SPEZIAL == 1);
        Agg_MarketableAssets_Spezial(t, k)      = sum(vect(Portfolios(idxWhereArtmittelSpezFund, :)));
        Agg_OtherAssets_Spezial(t, k)           = sum(vect(Portfolios_OtherAssets(idxWhereArtmittelSpezFund, :)));
        Agg_FundShares_Spezial(t, k)            = sum(vect(Portfolios_FundShares(idxWhereArtmittelSpezFund, :)));
    end
    
    clear idxWhereArtmittelPubFund idxWhereArtmittelSpezFund artmittel k;
    
    % Compute overall share of marketable assets, fund shares and other assets over time
    TotalShare_MarketableAssets(t)      = sum(Agg_MarketableAssets_Publikum(t, :) + Agg_MarketableAssets_Spezial(t, :)) / Agg_TotalAssets(t, 2);    
    TotalShare_OtherAssets(t)           = sum(Agg_OtherAssets_Publikum(t, :) + Agg_OtherAssets_Spezial(t, :)) / Agg_TotalAssets(t, 2);    
    TotalShare_FundShares(t)            = sum(Agg_FundShares_Publikum(t, :) + Agg_FundShares_Spezial(t, :)) / Agg_TotalAssets(t, 2);
        
    % Identify empty portfolios (funds that hold neighter marketable assets nor fundshares or other assets)
    idxPortfolioNotEmpty = find(nansum(Portfolios, 2) ~= 0 | nansum(Portfolios_FundShares, 2) ~= 0 | nansum(Portfolios_OtherAssets, 2) ~= 0);
    
        
    %% Save fund-level characteristics
    Fund_Artmittel(t, fund_data.fundid)           = fund_data.artmittel;
    Fund_Spezial(t, fund_data.fundid)             = fund_data.SPEZIAL;
    Fund_Fondsverm(t, fund_data.fundid)           = fund_data.FONDSVERM;
    Fund_Bilanzsumme(t, fund_data.fundid)         = fund_data.bilanzsumme;
    Fund_Leverage(t, fund_data.fundid)            = fund_data.leverage;
    Fund_MarketableAssets(t, fund_data.fundid)    = sum(Portfolios');
    Fund_OtherAssets(t, fund_data.fundid)         = sum(Portfolios_OtherAssets')';
    Fund_FundShares(t, fund_data.fundid)          = sum(Portfolios_FundShares');
    Fund_TotalAssets(t, fund_data.fundid)         = Fund_MarketableAssets(t, fund_data.fundid) + Fund_OtherAssets(t, fund_data.fundid) + Fund_FundShares(t, fund_data.fundid);
    Fund_Cash(t, fund_data.fundid)                = Portfolios(:, end)';
        
    
    %% Compute funds' portfolios after look-through   
    
    % Generate look-through portfolios
    [Portfolios_LookThrough, Portfolios_FundShares_LookThrough, Portfolios_OtherAssets_LookThrough] = PortfolioLookthrough_ConnFunds_Analytical(Portfolios, Portfolios_FundShares, sum(Portfolios_OtherAssets, 2));
    
    % For analysis of portfolio liquidity before and after look-through, build adjusted portfolio matrix (including only securities with known amihud ratio)
    if umonth(t) >= 201512
                  
        idxPriceImpact       = find(~isnan(PriceImpact));

        % First, portfolio before look-through

        Portfolios_Adjusted  = Portfolios(:, idxPriceImpact);
        PriceImpact_Adjusted = PriceImpact(idxPriceImpact);
        
        ... kick out cash
        Portfolios_Adjusted  = Portfolios_Adjusted(:, 1:end-1);
        PriceImpact_Adjusted = PriceImpact_Adjusted(1:end-1);
        
        M_NoLookThrough = zeros(size(Portfolios_Adjusted));
        M_NoLookThrough(sum(Portfolios_Adjusted') ~= 0, :) = Portfolios_Adjusted(sum(Portfolios_Adjusted') ~= 0, :) ./ repmat(sum(Portfolios_Adjusted(sum(Portfolios_Adjusted') ~= 0, :)')', 1, size(Portfolios_Adjusted, 2)); % matrix M
        
        idxHasNoMarketableAssets = find(sum(M_NoLookThrough, 2) == 0);
        M_NoLookThrough(idxHasNoMarketableAssets, :) = NaN;
        
        Fund_PriceImpact_NoLookThrough(t, fund_data.fundid)         = (M_NoLookThrough * PriceImpact_Adjusted)';
        Fund_PriceImpact_NoLookThrough(t, idxHasNoMarketableAssets) = NaN;
        
        % Second, portfolio after look-through

        ... kick out assets without price impact estimate       
        Portfolios_LookThrough_Adjusted = Portfolios_LookThrough(:, idxPriceImpact);
        
        ... kick out cash
        Portfolios_LookThrough_Adjusted = Portfolios_LookThrough_Adjusted(:, 1:end-1);
        
        M_LookThrough = zeros(size(Portfolios_LookThrough_Adjusted));
        M_LookThrough(sum(Portfolios_LookThrough_Adjusted') ~= 0, :) = Portfolios_LookThrough_Adjusted(sum(Portfolios_LookThrough_Adjusted') ~= 0, :) ./ repmat(sum(Portfolios_LookThrough_Adjusted(sum(Portfolios_LookThrough_Adjusted') ~= 0, :)')', 1, size(Portfolios_LookThrough_Adjusted, 2)); % matrix M
        
        idxHasNoMarketableAssets = find(sum(M_LookThrough, 2) == 0);
        M_LookThrough(idxHasNoMarketableAssets, :) = NaN;
        
        Fund_PriceImpact_LookThrough(t, fund_data.fundid)         = (M_LookThrough * PriceImpact_Adjusted)';
        Fund_PriceImpact_LookThrough(t, idxHasNoMarketableAssets) = NaN;
    end
    
    % Compute fund-level HHI
    Portfolio_Shares             = [Portfolios, Portfolios_FundShares] ./ sum([Portfolios, Portfolios_FundShares], 2);
    Portfolio_SharesDirect       = Portfolios ./ sum(Portfolios, 2);
    Portfolio_Shares_LookThrough = [Portfolios_LookThrough] ./ sum([Portfolios_LookThrough], 2);
    
    Fund_Weight             = sum([Portfolios, Portfolios_FundShares], 2) ./ sum(sum([Portfolios, Portfolios_FundShares]));
    Fund_WeightDirect       = sum(Portfolios, 2) ./ sum(sum(Portfolios));
    Fund_Weight_LookThrough = sum([Portfolios_LookThrough, Portfolios_FundShares_LookThrough], 2) ./ sum(sum([Portfolios_LookThrough, Portfolios_FundShares_LookThrough]));
    
    HHI_NoLookThrough       = nansum(Portfolio_Shares .* Portfolio_Shares, 2);
    HHI_NoLookThroughDirect = nansum(Portfolio_SharesDirect .* Portfolio_SharesDirect, 2);
    HHI_LookThrough         = nansum(Portfolio_Shares_LookThrough .* Portfolio_Shares_LookThrough, 2);
    
    Fund_HHI_NoLookThrough(t, ismember(ufund, uinvestor))       = HHI_NoLookThrough';
    Fund_HHI_NoLookThroughDirect(t, ismember(ufund, uinvestor)) = HHI_NoLookThroughDirect';
    Fund_HHI_LookThrough(t, ismember(ufund, uinvestor))         = HHI_LookThrough';    

    % Compute fund-level number of securities held 
    NrSecurities_NoLookThrough          = sum(Portfolios ~= 0, 2) + sum(Portfolios_FundShares ~= 0, 2);
    NrSecurities_NoLookThroughDirect    = sum(Portfolios ~= 0, 2);
    NrSecurities_LookThrough            = sum(Portfolios_LookThrough ~= 0, 2);

    Fund_NrSecurities_NoLookThrough(t, ismember(ufund, uinvestor))          = NrSecurities_NoLookThrough';
    Fund_NrSecurities_NoLookThroughDirect(t, ismember(ufund, uinvestor))    = NrSecurities_NoLookThroughDirect';    
    Fund_NrSecurities_LookThrough(t, ismember(ufund, uinvestor))            = NrSecurities_LookThrough';

    % Do some housekeeping
    clear fund_Holdings* investor tt noISIN_assettype idxWhereFund idxWhereUwpkenn idxWhereWPKENN ISIN_DE ISIN_FundShares isin_funds ratio;
    
    
    %% Save funds' reported portfolios and funds' portfolios after look-through
    save(strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\', num2str(umonth(t)), '_LookThroughAll'), '-v7.3');
    
end


%% Save fund-level data
save(strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\FundLevel_Data'), 'Agg_*', 'Fund_*', 'umonth*', 'ufund', 'TotalShare_*', 'Tmonth');


%%  ===================== Section 3: Generate fund-month panel for Amihud, HHI, Securities held and portfolio splits by asset type and investment regional (reported versus look-through) =====================

disp('Start generating Fund-Month-Panel...')

load(strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\FundLevel_Data'));

fund_month_panel = [];

for t = 1 : Tmonth-1
    
    tic
    
    t
    
    load(strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\', num2str(umonth(t)), '_LookThroughAll'), 'uinvestor', 'uwpkenn', 'data', 'Portfolios', 'Portfolios_LookThrough', 'Portfolios_OtherAssets', 'Portfolios_OtherAssets_LookThrough', 'Portfolios_FundShares', 'Portfolios_FundShares_LookThrough', 'Portfolio_Shares', 'Portfolio_Shares_LookThrough', 'HHI_NoLookThrough', 'HHI_NoLookThroughDirect', 'HHI_LookThrough', 'NrSecurities_NoLookThrough', 'NrSecurities_NoLookThroughDirect', 'NrSecurities_LookThrough', 'WP_AssetType', 'WP_IssuerType', 'WP_IssuerCountry');
    
    
    %% Get fund data
    fund_data = data(data.DATUM == umonth(t) & data.leverage >= 0 & ~isinf(data.leverage) & ~isnan(data.leverage), :);
    fund_data = sortrows(fund_data, 'ISIN');
    
    % Identify and kill empty portfolios (funds that hold neither marketable/non-marketable assets nor fundshares)
    idxPortfolioEmpty = find(nansum(Portfolios, 2) == 0 & nansum(Portfolios_FundShares, 2) == 0 & nansum(Portfolios_OtherAssets, 2) == 0);
    
    % Identify and kill funds that are not part of the fund crossholdings network (i.e., that are not held by other funds and that do not hold fund shares themselves)
    idxHoldsNoFundshares = find((sum(Portfolios_FundShares, 1) == 0)' & sum(Portfolios_FundShares, 2) == 0);
    
    kill = unique([idxPortfolioEmpty; idxHoldsNoFundshares]);
       
    fund_data(kill, :)                                  = [];
    Portfolios(kill, :)                                 = [];
    Portfolios_LookThrough(kill, :)                     = [];
    Portfolios_OtherAssets(kill, :)                     = [];
    Portfolios_OtherAssets_LookThrough(kill, :)         = [];
    Portfolios_FundShares(kill, :)                      = [];
    Portfolios_FundShares(:, kill)                      = [];
    Portfolios_FundShares_LookThrough(kill, :)          = [];
    Portfolios_FundShares_LookThrough(:, kill)          = [];
    Portfolio_Shares(kill, :)                           = [];
    Portfolio_Shares_LookThrough(kill, :)               = [];
    uinvestor(kill, :)                                  = [];
    HHI_NoLookThrough(kill, :)                          = [];
    HHI_NoLookThroughDirect(kill, :)                    = [];
    HHI_LookThrough(kill, :)                            = [];
    NrSecurities_NoLookThrough(kill, :)                 = [];
    NrSecurities_NoLookThroughDirect(kill, :)           = [];
    NrSecurities_LookThrough(kill, :)                   = [];
            
    tmp_fund_month_panel                    = table();
    tmp_fund_month_panel.DATUM              = repmat(umonth(t), length(uinvestor), 1);
    tmp_fund_month_panel.SPEZIAL            = fund_data.SPEZIAL;
    tmp_fund_month_panel.artmittel          = fund_data.artmittel;
    tmp_fund_month_panel.ISIN               = uinvestor;
    tmp_fund_month_panel.HHI                = HHI_NoLookThrough;
    tmp_fund_month_panel.HHI_Direct         = HHI_NoLookThroughDirect;
    tmp_fund_month_panel.HHI_LT             = HHI_LookThrough;
    tmp_fund_month_panel.NrSecurities       = NrSecurities_NoLookThrough;
    tmp_fund_month_panel.NrSecuritiesDirect = NrSecurities_NoLookThroughDirect;
    tmp_fund_month_panel.NrSecurities_LT    = NrSecurities_LookThrough;
    tmp_fund_month_panel.Amihud             = repmat(NaN, length(uinvestor), 1);
    tmp_fund_month_panel.Amihud_LT          = repmat(NaN, length(uinvestor), 1);
    
    
    %% Again, if available, get amihud ratios 
    if umonth(t) >= 201512    
       
        % Again, load security-level amihud ratios. Based on CSDB data, these are computed as described in the Discussion Paper version of this paper: 
        % https://www.bundesbank.de/resource/blob/842638/e3d0407c607b42420c9eb251cf9c7953/mL/2020-08-28-dkp-48-data.pdf
        CSDB_data = load(strcat(projectPath, 'Data\CSDB\mat\Amihud_', num2str(umonth(t))));
        CSDB_data = CSDB_data.data;
        
        total_security_share               = cellstr(CSDB_data.ESA_INS_2010);
        CSDB_assettype  = 1 * startsWith(total_security_share, 'F_3') + ...  % bond
            2 * startsWith(total_security_share, 'F_51') + ... % equity
            3 * startsWith(total_security_share, 'F_52');      % fund shares
        
        total_security_share               = cellstr(CSDB_data.ESA_ISSUER_2010);
        CSDB_issuertype = total_security_share;
        clear x;
        
        PriceImpact             = NaN(length(uwpkenn), 1);
        PriceImpact_AssetType   = NaN(length(uwpkenn), 1);
        PriceImpact_AssetSector = cell(length(uwpkenn), 1);
        
        % Find ISINs of marketable assets (uins_bonds / uins_equities) from CSDB data in uwpkenn
        [~, idxWhereCSDBIsin] = ismember(uwpkenn, CSDB_data.ISIN);
        
        PriceImpact(idxWhereCSDBIsin > 0) = CSDB_data.amihud_proxy1(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));
        
        % Add cash
        PriceImpact = [PriceImpact; 0];   
        
        % Get instrument type from CSDB for each security position with amihud ratios available
        PriceImpact_AssetType(idxWhereCSDBIsin > 0)              = CSDB_assettype(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));  
        PriceImpact_AssetType(isnan(PriceImpact_AssetType) == 1) = 3; % other asset
        PriceImpact_AssetSector(idxWhereCSDBIsin > 0)            = CSDB_issuertype(idxWhereCSDBIsin(idxWhereCSDBIsin > 0));
        
        clear idx* asset investor fund_Holdings* tt CSDB* asset_type;
        

        %% For assets with missing amihud ratios: check whether previous month is available. If so, replace by that value.
        if t > 1 
            i               = find(isnan(PriceImpact) == 1);
            uwpkenn_missing = uwpkenn(i);
            
            CSDB_data_Lag   = load(strcat(projectPath, 'Data\CSDB\mat\Amihud_', num2str(umonth(t - 1)))); 
            CSDB_data_Lag   = CSDB_data_Lag.data;
            
            [~, idxWhereUwpkennMissing] = ismember(CSDB_data_Lag.ISIN, uwpkenn_missing);
            amihud                      = NaN(length(uwpkenn_missing), 1);
            
            amihud(idxWhereUwpkennMissing(idxWhereUwpkennMissing > 0)) = CSDB_data_Lag.amihud_proxy1(idxWhereUwpkennMissing > 0);
            
            PriceImpact(i) = amihud;
            
            clear i uwpkenn_missing CSDB_data_Lag idxWhereUwpkennMissing amihud;
        end
        
        %  Winsorize amihud ratios
        idxWhereAssetType               = find(PriceImpact_AssetType == 2);
        tmp                             = PriceImpact(idxWhereAssetType);
        q                               = quantile(tmp, threshold_priceimpact_equities);
        tmp(tmp > q)                    = q;
        PriceImpact(idxWhereAssetType)  = tmp;
 
        clear idxWhereAssetType tmp q;
                
        % Build adjusted matrices for amihud ratios
        
        ... 1. reported portfolios

        % Kick out assets without amihud ratio
        idxPriceImpact       = find(~isnan(PriceImpact));
        Portfolios_Adjusted  = Portfolios(:, idxPriceImpact);
        PriceImpact_Adjusted = PriceImpact(idxPriceImpact);
        
        % Kick out cash
        Portfolios_Adjusted  = Portfolios_Adjusted(:, 1:end-1);
        PriceImpact_Adjusted = PriceImpact_Adjusted(1:end-1);
        
        ... 2. portfolios after look-through

        % Kick out assets without amihud ratio
        Portfolios_LookThrough_Adjusted = Portfolios_LookThrough(:, idxPriceImpact);
        
        % Kick out cash
        Portfolios_LookThrough_Adjusted = Portfolios_LookThrough_Adjusted(:, 1:end-1);
        
        fund_security_weight    = Portfolios_Adjusted ./ sum(Portfolios_Adjusted, 2);
        fund_security_weight_LT = Portfolios_LookThrough_Adjusted ./ sum(Portfolios_LookThrough_Adjusted, 2);
        
        % Compute price impact of selling securities worth €100 million
        tmp_fund_month_panel.Amihud       = (fund_security_weight * PriceImpact_Adjusted) * 100000000;
        tmp_fund_month_panel.Amihud_LT    = (fund_security_weight_LT * PriceImpact_Adjusted) * 100000000;
        
    end
    
    
    %% Compute portfolio holdings as reported and after looking through fund shares
    
    % Specify list of developed countries (as for price impact regressions)
    developedCountries = {'AU', 'AT','BE', 'CA', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'IS', 'IE', 'IL', 'IT', 'JP', 'LU', 'NL', 'NZ', 'NO', 'PT', 'SI', 'KR', 'ES', 'SE', 'SG', 'CH', 'US', 'GB'};
       
    % 1. Bonds
    whereSovereignBonds             = find(startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3'));
    whereNonSovereignBonds          = find(~startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3'));
    whereSovereignBondsEME          = find(startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3') & ismember(WP_IssuerCountry, developedCountries));
    whereSovereignBonds_Non_EME     = find(startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3') & ~ismember(WP_IssuerCountry, developedCountries));
    whereNonSovereignBondsEME       = find(~startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3') & ismember(WP_IssuerCountry, developedCountries));
    whereNonSovereignBonds_Non_EME  = find(~startsWith(WP_IssuerType, 'S_13') & startsWith(WP_AssetType, 'F_3') & ~ismember(WP_IssuerCountry, developedCountries));
    
    % 2. Equities
    whereEquities         = find(startsWith(WP_AssetType, 'F_51'));
    whereEquitiesEME      = find(startsWith(WP_AssetType, 'F_51') & ~ismember(WP_IssuerCountry, developedCountries));
    whereEquitiesNon_EME  = find(startsWith(WP_AssetType, 'F_51') & ismember(WP_IssuerCountry, developedCountries));
    
    % 3. Foreing fund shares
    whereForeignFundShares     = find(startsWith(WP_AssetType, 'F_52') & ~ismember(WP_IssuerCountry, 'DE'));
    
    % 4. Domestic / non-domestic emerging market economy / non-domestic non-emerging markets economy
    whereDomestic            = find(ismember(WP_IssuerCountry, 'DE') & ~startsWith(WP_AssetType, 'F_52'));
    whereNonDomesticEME      = find(~ismember(WP_IssuerCountry, developedCountries) & ~startsWith(WP_AssetType, 'F_52'));
    whereNonDomestic_Non_EME = find(ismember(WP_IssuerCountry, developedCountries) & ~ismember(WP_IssuerCountry, 'DE') & ~startsWith(WP_AssetType, 'F_52'));
    
    % Compute €-holdings (reported portfolio vs look-through portfolio)
    tmp_fund_month_panel.SovereignBonds       = sum(Portfolios(:, whereSovereignBonds), 2);
    tmp_fund_month_panel.SovereignBonds_LT    = sum(Portfolios_LookThrough(:, whereSovereignBonds), 2);
    
    tmp_fund_month_panel.NonSovereignBonds    = sum(Portfolios(:, whereNonSovereignBonds), 2);
    tmp_fund_month_panel.NonSovereignBonds_LT = sum(Portfolios_LookThrough(:, whereNonSovereignBonds), 2);
    
    tmp_fund_month_panel.Equities             = sum(Portfolios(:, whereEquities), 2);
    tmp_fund_month_panel.Equities_LT         = sum(Portfolios_LookThrough(:, whereEquities), 2);
    
    tmp_fund_month_panel.ForeignFundShares    = sum(Portfolios(:, whereForeignFundShares), 2);
    tmp_fund_month_panel.ForeignFundShares_LT = sum(Portfolios_LookThrough(:, whereForeignFundShares), 2);
    
    tmp_fund_month_panel.GerFundShares        = sum(Portfolios_FundShares(:, :), 2);
    tmp_fund_month_panel.GerFundShares_LT     = sum(Portfolios_FundShares_LookThrough(:, :), 2);
    
    tmp_fund_month_panel.Cash                 = Portfolios(:, end);
    tmp_fund_month_panel.Cash_LT              = Portfolios_LookThrough(:, end);
    
    tmp_fund_month_panel.Domestic             = sum(Portfolios(:, whereDomestic), 2);
    tmp_fund_month_panel.Domestic_LT          = sum(Portfolios_LookThrough(:, whereDomestic), 2);
    
    tmp_fund_month_panel.NonDomesticEME       = sum(Portfolios(:, whereNonDomesticEME), 2);
    tmp_fund_month_panel.NonDomesticEME_LT    = sum(Portfolios_LookThrough(:, whereNonDomesticEME), 2);
    
    tmp_fund_month_panel.NonDomestic_Non_EME    = sum(Portfolios(:, whereNonDomestic_Non_EME), 2);
    tmp_fund_month_panel.NonDomestic_Non_EME_LT = sum(Portfolios_LookThrough(:, whereNonDomestic_Non_EME), 2);
    
    tmp_fund_month_panel.Total    = tmp_fund_month_panel.SovereignBonds + tmp_fund_month_panel.NonSovereignBonds + tmp_fund_month_panel.Equities + tmp_fund_month_panel.ForeignFundShares + tmp_fund_month_panel.GerFundShares + tmp_fund_month_panel.Cash;
    tmp_fund_month_panel.Total_LT = tmp_fund_month_panel.SovereignBonds_LT + tmp_fund_month_panel.NonSovereignBonds_LT + tmp_fund_month_panel.Equities_LT + tmp_fund_month_panel.ForeignFundShares_LT + tmp_fund_month_panel.GerFundShares_LT + tmp_fund_month_panel.Cash_LT;
    
    % Compute %-holdings shares
    tmp_fund_month_panel.Pct_SovereignBonds       = (tmp_fund_month_panel.SovereignBonds ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_SovereignBonds_LT    = (tmp_fund_month_panel.SovereignBonds_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_NonSovereignBonds       = (tmp_fund_month_panel.NonSovereignBonds ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_NonSovereignBonds_LT    = (tmp_fund_month_panel.NonSovereignBonds_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_Equities       = (tmp_fund_month_panel.Equities ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_Equities_LT    = (tmp_fund_month_panel.Equities_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_ForeignFundShares       = (tmp_fund_month_panel.ForeignFundShares ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_ForeignFundShares_LT    = (tmp_fund_month_panel.ForeignFundShares_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_GerFundShares       = (tmp_fund_month_panel.GerFundShares ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_GerFundShares_LT    = (tmp_fund_month_panel.GerFundShares_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_Cash       = (tmp_fund_month_panel.Cash ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_Cash_LT    = (tmp_fund_month_panel.Cash_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_Domestic       = (tmp_fund_month_panel.Domestic ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_Domestic_LT    = (tmp_fund_month_panel.Domestic_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_NonDomesticEME       = (tmp_fund_month_panel.NonDomesticEME ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_NonDomesticEME_LT    = (tmp_fund_month_panel.NonDomesticEME_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    tmp_fund_month_panel.Pct_NonDomestic_Non_EME       = (tmp_fund_month_panel.NonDomestic_Non_EME ./ tmp_fund_month_panel.Total) .* 100;
    tmp_fund_month_panel.Pct_NonDomestic_Non_EME_LT    = (tmp_fund_month_panel.NonDomestic_Non_EME_LT ./ tmp_fund_month_panel.Total_LT) .* 100;
    
    % If funds dont have assets after look-through, set their holdings to zero (from NaN)
    tmp_fund_month_panel.Pct_SovereignBonds_LT(tmp_fund_month_panel.Total_LT == 0)      = 0;
    tmp_fund_month_panel.Pct_NonSovereignBonds_LT(tmp_fund_month_panel.Total_LT == 0)   = 0;
    tmp_fund_month_panel.Pct_Equities_LT(tmp_fund_month_panel.Total_LT == 0)            = 0;
    tmp_fund_month_panel.Pct_ForeignFundShares_LT(tmp_fund_month_panel.Total_LT == 0)   = 0;
    tmp_fund_month_panel.Pct_GerFundShares_LT(tmp_fund_month_panel.Total_LT == 0)       = 0;
    tmp_fund_month_panel.Pct_Cash_LT(tmp_fund_month_panel.Total_LT == 0)                = 0;
    tmp_fund_month_panel.Pct_Domestic_LT(tmp_fund_month_panel.Total_LT == 0)            = 0;
    tmp_fund_month_panel.Pct_NonDomesticEME_LT(tmp_fund_month_panel.Total_LT == 0)      = 0;
    tmp_fund_month_panel.Pct_NonDomestic_Non_EME_LT(tmp_fund_month_panel.Total_LT == 0) = 0;
    
    fund_month_panel = [fund_month_panel; tmp_fund_month_panel];
    
    toc
    
end


%% Save fund-month panel table
save(projectPath, 'Data\LookThroughVsReportedPortfolio\fund_month_panel', 'fund_month_panel');


%%  =============================================================== Section 4: Construct Table 2: Reported versus look-through portfolios. ===============================================================


disp('Start generating table for look-through results...')

tic

% Load fund-month panel
load(projectPath, 'Data\LookThroughVsReportedPortfolio\fund_month_panel');
writetable(fund_month_panel, strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\fund_month_panel.csv'))

% Build Table 2: Reported versus look-through portfolios.
for subset = {'All', 'Inst', 'Retail', 'Inst_Mixed'}
    
    % All funds
    if ismember(subset{1}, 'All')
        subset_fund_month_panel = fund_month_panel;
    % Only retail funds
    elseif ismember(subset{1}, 'Retail')
        subset_fund_month_panel = fund_month_panel(fund_month_panel.SPEZIAL == 0, :);
    % Only institutional funds
    elseif ismember(subset{1}, 'Inst')
        subset_fund_month_panel = fund_month_panel(fund_month_panel.SPEZIAL == 1, :);
    % Only institutional mixed funds
    elseif ismember(subset{1}, 'Inst_Mixed')
        subset_fund_month_panel = fund_month_panel(fund_month_panel.SPEZIAL == 1 & fund_month_panel.artmittel == 3, :);
    end    
    
    % Winsorize fund-level illiquidity and concentration measures:

    ... 1. fund-level illiquidity

    subset_fund_month_panel.WS_Amihud = subset_fund_month_panel.Amihud;
    q01   = quantile(subset_fund_month_panel.Amihud, 0.01);
    q99   = quantile(subset_fund_month_panel.Amihud, 0.99);
    subset_fund_month_panel.WS_Amihud(subset_fund_month_panel.WS_Amihud < q01) = q01;
    subset_fund_month_panel.WS_Amihud(subset_fund_month_panel.WS_Amihud > q99) = q99;
    
    subset_fund_month_panel.WS_Amihud_LT = subset_fund_month_panel.Amihud_LT;
    q01   = quantile(subset_fund_month_panel.Amihud_LT, 0.01);
    q99   = quantile(subset_fund_month_panel.Amihud_LT, 0.99);
    subset_fund_month_panel.WS_Amihud_LT(subset_fund_month_panel.WS_Amihud_LT < q01) = q01;
    subset_fund_month_panel.WS_Amihud_LT(subset_fund_month_panel.WS_Amihud_LT > q99) = q99;
    
    subset_fund_month_panel.WS_Diff_Amihud = (subset_fund_month_panel.WS_Amihud - subset_fund_month_panel.WS_Amihud_LT);
    
    ... 2. fund level concentration

    subset_fund_month_panel.WS_HHI = subset_fund_month_panel.HHI;
    q01   = quantile(subset_fund_month_panel.HHI, 0.01);
    q99   = quantile(subset_fund_month_panel.HHI, 0.99);
    subset_fund_month_panel.WS_HHI(subset_fund_month_panel.WS_HHI < q01) = q01;
    subset_fund_month_panel.WS_HHI(subset_fund_month_panel.WS_HHI > q99) = q99;

    subset_fund_month_panel.WS_HHI_Direct = subset_fund_month_panel.HHI_Direct;
    q01   = quantile(subset_fund_month_panel.HHI_Direct, 0.01);
    q99   = quantile(subset_fund_month_panel.HHI_Direct, 0.99);
    subset_fund_month_panel.WS_HHI_Direct(subset_fund_month_panel.WS_HHI_Direct < q01) = q01;
    subset_fund_month_panel.WS_HHI_Direct(subset_fund_month_panel.WS_HHI_Direct > q99) = q99;
    
    subset_fund_month_panel.WS_HHI_LT = subset_fund_month_panel.HHI_LT;
    q01   = quantile(subset_fund_month_panel.HHI_LT, 0.01);
    q99   = quantile(subset_fund_month_panel.HHI_LT, 0.99);
    subset_fund_month_panel.WS_HHI_LT(subset_fund_month_panel.WS_HHI_LT < q01) = q01;
    subset_fund_month_panel.WS_HHI_LT(subset_fund_month_panel.WS_HHI_LT > q99) = q99;
    
    subset_fund_month_panel.WS_Diff_HHI         = (subset_fund_month_panel.WS_HHI - subset_fund_month_panel.WS_HHI_LT);   
    subset_fund_month_panel.WS_Diff_HHI_Direct  = (subset_fund_month_panel.WS_HHI_Direct - subset_fund_month_panel.WS_HHI_LT);


    %% Get matched pairs of funds before and after look-through
    include_HHI                     = find(~isnan(subset_fund_month_panel.WS_HHI) & ~isnan(subset_fund_month_panel.WS_HHI_LT));
    include_HHI_Direct              = find(~isnan(subset_fund_month_panel.WS_HHI_Direct) & ~isnan(subset_fund_month_panel.WS_HHI_LT));
    include_NrSecurities            = find(~isnan(subset_fund_month_panel.NrSecurities) & ~isnan(subset_fund_month_panel.NrSecurities_LT));
    include_NrSecuritiesDirect      = find(~isnan(subset_fund_month_panel.NrSecuritiesDirect) & ~isnan(subset_fund_month_panel.NrSecurities_LT));
    include_Amihud                  = find(~isnan(subset_fund_month_panel.WS_Amihud) & ~isnan(subset_fund_month_panel.WS_Amihud_LT));
    include_Pct_SovereignBonds      = find(~isnan(subset_fund_month_panel.Pct_SovereignBonds) & ~isnan(subset_fund_month_panel.Pct_SovereignBonds_LT));
    include_Pct_NonSovereignBonds   = find(~isnan(subset_fund_month_panel.Pct_NonSovereignBonds) & ~isnan(subset_fund_month_panel.Pct_NonSovereignBonds_LT));
    include_Pct_Equities            = find(~isnan(subset_fund_month_panel.Pct_Equities) & ~isnan(subset_fund_month_panel.Pct_Equities_LT));
    include_Pct_ForeignFundShares   = find(~isnan(subset_fund_month_panel.Pct_ForeignFundShares) & ~isnan(subset_fund_month_panel.Pct_ForeignFundShares_LT));
    include_Pct_GerFundShares       = find(~isnan(subset_fund_month_panel.Pct_GerFundShares) & ~isnan(subset_fund_month_panel.Pct_GerFundShares_LT));
    include_Pct_Cash                = find(~isnan(subset_fund_month_panel.Pct_Cash) & ~isnan(subset_fund_month_panel.Pct_Cash_LT));
    include_Pct_Domestic            = find(~isnan(subset_fund_month_panel.Pct_Domestic) & ~isnan(subset_fund_month_panel.Pct_Domestic_LT));
    include_Pct_NonDomestic_Non_EME = find(~isnan(subset_fund_month_panel.Pct_NonDomestic_Non_EME) & ~isnan(subset_fund_month_panel.Pct_NonDomestic_Non_EME_LT));
    include_Pct_NonDomesticEME      = find(~isnan(subset_fund_month_panel.Pct_NonDomesticEME) & ~isnan(subset_fund_month_panel.Pct_NonDomesticEME_LT));
    
    
    %% Test for differences between reported portfolio and portfolio after look-through (paired ttest)
    [~, p_HHI]                      = ttest(subset_fund_month_panel.WS_HHI_LT(include_HHI), subset_fund_month_panel.WS_HHI(include_HHI));
    [~, p_HHI_Direct]               = ttest(subset_fund_month_panel.WS_HHI_LT(include_HHI_Direct), subset_fund_month_panel.WS_HHI_Direct(include_HHI_Direct));
    [~, p_NrSecurities]             = ttest(subset_fund_month_panel.NrSecurities_LT(include_NrSecurities), subset_fund_month_panel.NrSecurities(include_NrSecurities));
    [~, p_NrSecuritiesDirect]       = ttest(subset_fund_month_panel.NrSecurities_LT(include_NrSecuritiesDirect), subset_fund_month_panel.NrSecuritiesDirect(include_NrSecuritiesDirect));
    [~, p_Amihud]                   = ttest(subset_fund_month_panel.WS_Amihud_LT(include_Amihud), subset_fund_month_panel.WS_Amihud(include_Amihud));
    [~, p_Pct_SovereignBonds]       = ttest(subset_fund_month_panel.Pct_SovereignBonds(include_Pct_SovereignBonds), subset_fund_month_panel.Pct_SovereignBonds_LT(include_Pct_SovereignBonds));
    [~, p_Pct_NonSovereignBonds]    = ttest(subset_fund_month_panel.Pct_NonSovereignBonds(include_Pct_NonSovereignBonds), subset_fund_month_panel.Pct_NonSovereignBonds_LT(include_Pct_NonSovereignBonds));
    [~, p_Pct_Equities]             = ttest(subset_fund_month_panel.Pct_Equities(include_Pct_Equities), subset_fund_month_panel.Pct_Equities_LT(include_Pct_Equities));
    [~, p_Pct_ForeignFundShares]    = ttest(subset_fund_month_panel.Pct_ForeignFundShares(include_Pct_ForeignFundShares), subset_fund_month_panel.Pct_ForeignFundShares_LT(include_Pct_ForeignFundShares));
    [~, p_Pct_GerFundShares]        = ttest(subset_fund_month_panel.Pct_GerFundShares(include_Pct_GerFundShares), subset_fund_month_panel.Pct_GerFundShares_LT(include_Pct_GerFundShares));
    [~, p_Pct_Cash]                 = ttest(subset_fund_month_panel.Pct_Cash(include_Pct_Cash), subset_fund_month_panel.Pct_Cash_LT(include_Pct_Cash));
    [~, p_Pct_Domestic]             = ttest(subset_fund_month_panel.Pct_Domestic(include_Pct_Domestic), subset_fund_month_panel.Pct_Domestic_LT(include_Pct_Domestic));
    [~, p_Pct_NonDomestic_Non_EME]  = ttest(subset_fund_month_panel.Pct_NonDomestic_Non_EME(include_Pct_NonDomestic_Non_EME), subset_fund_month_panel.Pct_NonDomestic_Non_EME_LT(include_Pct_NonDomestic_Non_EME));
    [~, p_Pct_NonDomesticEME]       = ttest(subset_fund_month_panel.Pct_NonDomesticEME(include_Pct_NonDomesticEME), subset_fund_month_panel.Pct_NonDomesticEME_LT(include_Pct_NonDomesticEME));
    
    
    %% Construct result table
    LookThrough_Table = table();
    LookThrough_Table.Characteristic = {'HHI'; 'NrSecurities'; 'Amihud'; 'Pct_SovereignBonds'; ...
        'Pct_NonSovereignBonds'; 'Pct_Equities'; ...
        'Pct_ForeignFundShares'; 'Pct_GerFundShares'; 'Pct_Cash'; ...
        'Pct_DomesticAssets'; 'Pct_NonDomestic_Non_EME_Assets'; ...
        'Pct_NonDomestic_EME_Assets'};
    
    LookThrough_Table.Portfolio_Reported = [mean(subset_fund_month_panel.WS_HHI(include_HHI)); ...
        mean(subset_fund_month_panel.NrSecurities(include_NrSecurities)); ...
        mean(subset_fund_month_panel.WS_Amihud(include_Amihud)); ...
        mean(subset_fund_month_panel.Pct_SovereignBonds(include_Pct_SovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_NonSovereignBonds(include_Pct_NonSovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_Equities(include_Pct_Equities)); ...
        mean(subset_fund_month_panel.Pct_ForeignFundShares(include_Pct_ForeignFundShares)); ...
        mean(subset_fund_month_panel.Pct_GerFundShares(include_Pct_GerFundShares)); ...
        mean(subset_fund_month_panel.Pct_Cash(include_Pct_Cash)); ...
        mean(subset_fund_month_panel.Pct_Domestic(include_Pct_Domestic)); ...
        mean(subset_fund_month_panel.Pct_NonDomestic_Non_EME(include_Pct_NonDomestic_Non_EME)); ...
        mean(subset_fund_month_panel.Pct_NonDomesticEME(include_Pct_NonDomesticEME))];
    
    LookThrough_Table.Portfolio_LookThrough = [mean(subset_fund_month_panel.WS_HHI_LT(include_HHI)); ...
        mean(subset_fund_month_panel.NrSecurities_LT(include_NrSecurities)); ...
        mean(subset_fund_month_panel.WS_Amihud_LT(include_Amihud)); ...
        mean(subset_fund_month_panel.Pct_SovereignBonds_LT(include_Pct_SovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_NonSovereignBonds_LT(include_Pct_NonSovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_Equities_LT(include_Pct_Equities)); ...
        mean(subset_fund_month_panel.Pct_ForeignFundShares_LT(include_Pct_ForeignFundShares)); ...
        mean(subset_fund_month_panel.Pct_GerFundShares_LT(include_Pct_GerFundShares)); ...
        mean(subset_fund_month_panel.Pct_Cash_LT(include_Pct_Cash)); ...
        mean(subset_fund_month_panel.Pct_Domestic_LT(include_Pct_Domestic)); ...
        mean(subset_fund_month_panel.Pct_NonDomestic_Non_EME_LT(include_Pct_NonDomestic_Non_EME)); ...
        mean(subset_fund_month_panel.Pct_NonDomesticEME_LT(include_Pct_NonDomesticEME))];
    
    LookThrough_Table.Portfolio_Reported_minus_Portfolio_LookThrough = [mean(subset_fund_month_panel.WS_Diff_HHI(include_HHI)); ...
        mean(subset_fund_month_panel.NrSecurities(include_NrSecurities) - subset_fund_month_panel.NrSecurities_LT(include_NrSecurities));
        mean(subset_fund_month_panel.WS_Diff_Amihud(include_Amihud)); ...
        mean(subset_fund_month_panel.Pct_SovereignBonds(include_Pct_SovereignBonds) - subset_fund_month_panel.Pct_SovereignBonds_LT(include_Pct_SovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_NonSovereignBonds(include_Pct_NonSovereignBonds) - subset_fund_month_panel.Pct_NonSovereignBonds_LT(include_Pct_NonSovereignBonds)); ...
        mean(subset_fund_month_panel.Pct_Equities(include_Pct_Equities) - subset_fund_month_panel.Pct_Equities_LT(include_Pct_Equities)); ...
        mean(subset_fund_month_panel.Pct_ForeignFundShares(include_Pct_ForeignFundShares) - subset_fund_month_panel.Pct_ForeignFundShares_LT(include_Pct_ForeignFundShares)); ...
        mean(subset_fund_month_panel.Pct_GerFundShares(include_Pct_GerFundShares) - subset_fund_month_panel.Pct_GerFundShares_LT(include_Pct_GerFundShares)); ...
        mean(subset_fund_month_panel.Pct_Cash(include_Pct_Cash) - subset_fund_month_panel.Pct_Cash_LT(include_Pct_Cash)); ...
        mean(subset_fund_month_panel.Pct_Domestic(include_Pct_Domestic) - subset_fund_month_panel.Pct_Domestic_LT(include_Pct_Domestic)); ...
        mean(subset_fund_month_panel.Pct_NonDomestic_Non_EME(include_Pct_NonDomestic_Non_EME) - subset_fund_month_panel.Pct_NonDomestic_Non_EME_LT(include_Pct_NonDomestic_Non_EME)); ...
        mean(subset_fund_month_panel.Pct_NonDomesticEME(include_Pct_NonDomesticEME) - subset_fund_month_panel.Pct_NonDomesticEME_LT(include_Pct_NonDomesticEME))];
    
    LookThrough_Table.PVal = [p_HHI; p_NrSecurities; p_Amihud; p_Pct_SovereignBonds; ...
        p_Pct_NonSovereignBonds; p_Pct_Equities; ...
        p_Pct_ForeignFundShares; p_Pct_GerFundShares; p_Pct_Cash; ...
        p_Pct_Domestic; p_Pct_NonDomestic_Non_EME; ...
        p_Pct_NonDomesticEME];
    
    LookThrough_Table.N = [length(subset_fund_month_panel.WS_HHI_LT(include_HHI)); ...
        length(subset_fund_month_panel.NrSecurities(include_NrSecurities)); ...
        length(subset_fund_month_panel.WS_Amihud_LT(include_Amihud)); ...
        length(subset_fund_month_panel.Pct_SovereignBonds(include_Pct_SovereignBonds)); ...
        length(subset_fund_month_panel.Pct_NonSovereignBonds(include_Pct_NonSovereignBonds)); ...
        length(subset_fund_month_panel.Pct_Equities(include_Pct_Equities)); ...
        length(subset_fund_month_panel.Pct_ForeignFundShares(include_Pct_ForeignFundShares)); ...
        length(subset_fund_month_panel.Pct_GerFundShares(include_Pct_GerFundShares)); ...
        length(subset_fund_month_panel.Pct_Cash(include_Pct_Cash)); ...
        length(subset_fund_month_panel.Pct_Domestic(include_Pct_Domestic)); ...
        length(subset_fund_month_panel.Pct_NonDomestic_Non_EME(include_Pct_NonDomestic_Non_EME)); ...
        length(subset_fund_month_panel.Pct_NonDomesticEME(include_Pct_NonDomesticEME))];
    
    
    %% Save result table
    save(strcat(projectPath, 'Data\LookThroughVsReportedPortfolio\LookThrough_Table_', subset{1}), 'LookThrough_Table');
    writetable(LookThrough_Table, strcat(projectPath, 'Paper\Tables\Tab2_Reported versus look-through portfolios.xlsx'), 'Sheet', subset{1});
    
end

toc